package net.ufrog.common.dict;

import net.ufrog.common.Logger;
import net.ufrog.common.app.App;
import net.ufrog.common.cache.Caches;
import net.ufrog.common.utils.Strings;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * 字典工具
 * 
 * @author ultrafrog
 * @version 1.0, 2012-11-29
 * @since 1.0
 */
public class Dicts {

    private static final String CACHE = "cache_dict_";

    /** 构造函数 */
    private Dicts() {}

    /**
     * 元素映射
     *
     * @param type 类型
     * @return 元素映射表
     */
    @SuppressWarnings("unchecked")
    public static Map<Object, Elem> elements(Class<?> type) {
        Map<Object, Elem> elements = Caches.get(CACHE, type.getName(), Map.class);
        if (elements == null) {
            Logger.info("cache dictionary '%s' start...", type.getName());
            elements = new LinkedHashMap<>();

            for (Field field: type.getDeclaredFields()) {
                Element element = field.getAnnotation(Element.class);
                if (element != null) {
                    try {
                        Object key = field.get(type);
                        Elem elem = new Elem(element);
                        elements.put(key, elem);
                        Logger.info("cache dictionary '%s' field '%s: %s'.", type.getName(), key, elem.getName());
                    } catch (IllegalArgumentException | IllegalAccessException e) {
                        Logger.error(e.getMessage(), e);
                    }
                }
            }
            Caches.add(CACHE, type.getName(), elements);
            Logger.info("cache dictionary '%s' completed!", type.getName());
        }
        return elements;
    }

    /**
     * 元素映射<br>
     * 除去指定元素
     *
     * @param type 类型
     * @param excludes 排除键值数组
     * @return 元素映射
     */
    public static Map<Object, Elem> excludes(Class<?> type, Object... excludes) {
        Map<Object, Elem> copy = new LinkedHashMap<>(elements(type));
        Arrays.asList(excludes).forEach(copy::remove);
        return copy;
    }

    /**
     * 元素映射<br>
     * 仅包含指定元素
     *
     * @param type 类型
     * @param includes 包含键值数组
     * @return 元素映射
     */
    public static Map<Object, Elem> includes(Class<?> type, Object... includes) {
        Map<Object, Elem> copy = new LinkedHashMap<>(includes.length);
        Arrays.asList(includes).forEach(key -> copy.put(key, elements(type).get(key)));
        return copy;
    }

    /**
     * 元素名称
     *
     * @param key 代码
     * @param type 类型
     * @return 对应的元素名称
     */
    public static String name(Object key, Class<?> type) {
        Elem elem = elements(type).get(key);
        return (elem != null) ? elem.getName() : null;
    }

    /**
     * 元素名称
     *
     * @param key 代码
     * @param defaultValue 默认值
     * @param type 类型
     * @return 对应的元素名称
     */
    public static String name(Object key, String defaultValue, Class<?> type) {
        return Strings.empty(name(key, type), defaultValue);
    }

    /**
     * 元素代码
     *
     * @param key 代码
     * @param type 类型
     * @return 对应的元素代码
     */
    public static String code(Object key, Class<?> type) {
        return elements(type).get(key).getCode();
    }

    /**
     * 元素代码
     *
     * @param key 代码
     * @param defaultValue 默认值
     * @param type 类型
     * @return 对应的元素代码
     */
    public static String code(Object key, String defaultValue, Class<?> type) {
        return Strings.empty(code(key, type), defaultValue);
    }

    /**
     * 布尔值
     *
     * @author ultrafrog
     * @version 0.1, 2014-01-17
     * @since 0.1
     */
    public static final class Bool {

        @Element("否")
        public static final String FALSE	= "00";

        @Element("是")
        public static final String TRUE		= "01";
    }

    /**
     * 元素
     *
     * @author ultrafrog
     * @version 0.1, 2016-03-06
     * @since 0.1
     */
    public static final class Elem implements Serializable {

        /** 名称 */
        private String name;

        /** 代码 */
        private String code;

        /**
         * 构造函数
         *
         * @param element 元素注解
         */
        public Elem(Element element) {
            this.name = element.value().startsWith("@") ? App.message(element.value().substring(1)) : element.value();
            this.code = Strings.empty(element.code(), null);
        }

        /**
         * 读取名称
         *
         * @return 名称
         */
        public String getName() {
            return name;
        }

        /**
         * 读取代码
         *
         * @return 代码
         */
        public String getCode() {
            return code;
        }
    }
}
